// 版权所有2009 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package os

import (
	"errors"
	"internal/testlog"
	"runtime"
	"sync"
	"sync/atomic"
	"syscall"
	"time"
)

// ErrProcessDone表示进程已完成。
var ErrProcessDone = errors.New("os: process already finished")

// 进程存储有关StartProcess创建的进程的信息。
type Process struct {
	Pid    int
	handle uintptr      // 在Windows上以原子方式访问句柄
	isdone uint32       // 进程已成功等待，如果为真
	sigMu  sync.RWMutex // 则非零避免等待和信号
}

func newProcess(pid int, handle uintptr) *Process {
	p := &Process{Pid: pid, handle: handle}
	runtime.SetFinalizer(p, (*Process).Release)
	return p
}

func (p *Process) setDone() {
	atomic.StoreUint32(&p.isdone, 1)
}

func (p *Process) done() bool {
	return atomic.LoadUint32(&p.isdone) > 0
}

// ProcAttr保留将应用于StartProcess启动的新进程
// 的属性。
type ProcAttr struct {
	// 如果Dir为非空，则子项将在创建进程之前更改到目录中。
	Dir string
	// 如果Env为非nil，则以Environ返回的形式为
	// 新进程提供环境变量。
	// 如果为零，则使用Environ的结果。
	Env []string
	// Files指定新进程继承的打开文件。前三个条目分别对应于标准输入、标准输出和标准错误。根据底层操作系统的不同，一个实现可能支持额外的条目，
	// 。nil条目对应于进程启动时关闭的文件
	// 。
	// 在Unix系统上，StartProcess会将这些文件值
	// 更改为阻塞模式，这意味着SetDeadline将停止工作
	// 并且调用Close不会中断读或写操作。
	Files []*File

	// 特定于操作系统的进程创建属性。
	// 请注意，设置此字段意味着您的程序
	// 可能无法正确执行，甚至无法在某些
	// 操作系统上编译。
	Sys *syscall.SysProcAttr
}

// 信号表示操作系统信号。
// 通常的底层实现依赖于操作系统：
// 在Unix上是syscall.Signal。
type Signal interface {
	String() string
	Signal() // 区别于其他stringer 
}

// Getpid返回调用方的进程id。
func Getpid() int { return syscall.Getpid() }

// Getppid返回调用方父进程的进程id。
func Getppid() int { return syscall.Getppid() }

// FindProcess通过其pid查找正在运行的进程。
// 
// 它返回的进程可用于获取有关底层操作系统进程的信息
// 。
// 
// 在Unix系统上，FindProcess始终成功并返回给定pid的进程
// 无论该进程是否存在。
func FindProcess(pid int) (*Process, error) {
	return findProcess(pid)
}

// StartProcess使用程序、参数和属性启动新进程
// 由名称、argv和attr指定。在
// 新进程中，argv片将变成os.Args，因此它通常以程序名开始。
// 
// 如果调用的goroutine已使用runtime.LockOSThread锁定操作系统线程
// 并修改了任何可继承的操作系统级
// 线程状态（例如，Linux或Plan 9命名空间），则新的
// 进程将继承调用方的线程状态。
// 
// StartProcess是一个低级接口。os/exec包提供
// 更高级别的接口。
// 
// 如果有错误，则类型为*PathError。
func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
	testlog.Open(name)
	return startProcess(name, argv, attr)
}

// Release释放与进程p相关的任何资源，
// 使其在将来无法使用。
// 只有在未启用Wait时才需要调用Release。
func (p *Process) Release() error {
	return p.release()
}

// Kill导致进程立即退出。Kill不等待
// 进程实际退出。这只会杀死进程本身，而不是它可能启动的任何其他进程。
func (p *Process) Kill() error {
	return p.kill()
}

// 等待进程退出，然后返回描述其状态的
// ProcessState和错误（如果有）。
// 等待释放与进程关联的所有资源。在大多数操作系统上，进程必须是当前进程的子进程，否则将返回错误。
func (p *Process) Wait() (*ProcessState, error) {
	return p.wait()
}

// 信号向进程发送信号。
// 未在Windows上执行发送中断。
func (p *Process) Signal(sig Signal) error {
	return p.signal(sig)
}

// UserTime返回已退出进程及其子进程的用户CPU时间。
func (p *ProcessState) UserTime() time.Duration {
	return p.userTime()
}

// SystemTime返回已退出进程及其子进程的系统CPU时间。
func (p *ProcessState) SystemTime() time.Duration {
	return p.systemTime()
}

// Exited报告程序是否已退出。
func (p *ProcessState) Exited() bool {
	return p.exited()
}

// 成功报告程序是否成功退出，
// 例如Unix上的退出状态为0。
func (p *ProcessState) Success() bool {
	return p.success()
}

// Sys返回有关
// /这个过程。将其转换为相应的基础
// 类型，如Unix上的syscall.WaitStatus，以访问其内容。
func (p *ProcessState) Sys() interface{} {
	return p.sys()
}

// SysUsage返回有关已退出进程的依赖于系统的资源使用信息
// 已退出进程。将其转换为相应的基础
// 类型，如Unix上的*syscall.Rusage，以访问其内容。
// （在Unix上，*syscall.Rusage与
// /getrusage（2）手册页中定义的结构Rusage匹配。）
func (p *ProcessState) SysUsage() interface{} {
	return p.sysUsage()
}
